# -*- encoding:utf-8 -*-

# @Date  :2016-07-12
# @Author:金忠帅|二条（jinzhongshuai@antiy.cn）

import uuid
import random
import pickle
import datetime
from werkzeug.datastructures import CallbackDict
from flask.sessions import SessionMixin, SessionInterface
from flask import request
from config import config


def _get_new_sid():
    return uuid.uuid5(uuid.uuid4(), str(random.random)).get_hex()


class SessionObj(CallbackDict, SessionMixin):
    def __init__(self, initial=None, sid=None, new=False):
        def on_update(self):
            self.modified = True
        CallbackDict.__init__(self, initial, on_update)
        self.sid = sid
        self.new = new
        self.modified = False


class RedisSessionInterface(SessionInterface):
    serializer = pickle
    session_class = SessionObj

    def __init__(self, redis=None):
        self.redis = redis

    def open_session(self, app, request):
        '''接口:获取Session'''
        sessionid = request.cookies.get(app.session_cookie_name)
        if not sessionid:
            return self.session_class(sid=_get_new_sid(), new=True)
        sessiondata = self.redis.get(sessionid)
        if sessiondata is None:
            return self.session_class(sid=_get_new_sid(), new=True)
        sessiondata = self.serializer.loads(sessiondata)
        return self.session_class(sessiondata, sid=sessionid)

    def save_session(self, app, session, response):
        '''接口:保存Session'''
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)
        if not session:
            self.redis.delete(session.sid)
            if session.modified:
                response.delete_cookie(app.session_cookie_name, domain=domain, path=path)
            return
        httponly = self.get_cookie_httponly(app)
        secure = self.get_cookie_secure(app)
        expires = self.get_expiration_time(app, session)
        sessiondata = self.serializer.dumps(dict(session))
        self.redis.setex(session.sid, sessiondata,
                         int(expires.total_seconds()))
        response.set_cookie(app.session_cookie_name, session.sid,
                            expires=expires, httponly=httponly,
                            domain=domain, path=path, secure=secure)


class PostgresSessionInterface(SessionInterface):
    serializer = pickle
    session_class = SessionObj

    def __init__(self, pg_conn=None):
        self.pg_conn = pg_conn
        self.pg_cur = pg_conn.cursor()
        try:  # 清空数据库SESSION
            self.pg_cur.execute("delete from sys_session where (%s-r_time)>%s", (datetime.datetime.now(), str(int(config.sessionSaveTime))))
            self.pg_conn.commit()
        except Exception, e:
            self.pg_conn.rollback()
            raise e

    def open_session(self, app, request):
        """接口:获取Session"""
        sessionid = request.cookies.get(app.session_cookie_name)
        if not sessionid:
            return self.session_class(sid=_get_new_sid(), new=True)
        self.pg_cur.execute("""select userinfo, r_time from sys_session where token=%s""", (sessionid,))
        sessiondata = self.pg_cur.fetchone()
        if sessiondata is None or (datetime.datetime.now() - sessiondata[1]).total_seconds() > config.sessionSaveTime:
            try:  # 删除过期SESSION
                self.pg_cur.execute("delete from sys_session where (%s-r_time)>%s",
                                    (datetime.datetime.now(), str(int(config.sessionSaveTime))))
                self.pg_conn.commit()
            except Exception, e:
                self.pg_conn.rollback()
                raise e
            return self.session_class(sid=_get_new_sid(), new=True)
        sessiondata = self.serializer.loads(sessiondata[0])
        return self.session_class(sessiondata, sid=sessionid)

    def save_session(self, app, session, response):
        """接口:保存Session"""
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)
        if not session:
            try:  # 删除SESSION
                self.pg_cur.execute("""delete from sys_session where token=%s""", (session.sid,))
                self.pg_conn.commit()
            except Exception, e:
                self.pg_conn.rollback()
                raise e
            if session.modified:
                response.delete_cookie(app.session_cookie_name,
                                       domain=domain, path=path)
            return
        httponly = self.get_cookie_httponly(app)
        secure = self.get_cookie_secure(app)
        expires = self.get_expiration_time(app, session)
        sessiondata = self.serializer.dumps(dict(session))
        try:  # 保存/更新SESSION
            if session.new:
                self.pg_cur.execute("""insert into sys_session(token,userinfo, ip, user_name, r_time)
                                       values (%s, %s, %s, %s, %s)""", (session.sid, sessiondata, request.headers.get(config.ipType, None) if request.headers.get(config.ipType, None) else request.remote_addr, session['_currUser']['user']['user_name'], datetime.datetime.now()))
            else:
                self.pg_cur.execute("""update sys_session set userinfo=%s,r_time=%s where token=%s""", (sessiondata, datetime.datetime.now(), session.sid))
            self.pg_conn.commit()
        except Exception, e:
            self.pg_conn.rollback()
            raise e
        response.set_cookie(app.session_cookie_name, session.sid,
                            expires=expires, httponly=httponly,
                            domain=domain, path=path, secure=secure)
